#include <algorithm>
#include <iostream>
#include <ctime>
#include "Commander.h"

#define intPair pair<int,int>

using namespace std;

Commander::~Commander(void)
{
	if (dist2Island != NULL) {
		for (int i = 0; i < 5; ++i)
			delete[] dist2Island[i];
		delete[] dist2Island;
	}
}

Commander::Commander(void) {
	dist2Island = NULL;
	lastActionTime = -1;
}

void Commander::updateOurs( ShipInfo& ship )
{
	update(ship, ours);
}

void Commander::updateEnemies( ShipInfo& ship ) {
	update(ship, enemies);
}


void Commander::updateIslands( vector<ResourceInfo>& islands )
{
	for (unsigned int i=0; i<islands.size(); ++i)
		update(islands[i], this->islands);
}

template<typename T1, typename T2>
void Commander::update( T1& ship, vector<T2>& force )
{
	bool updated = false;
	for (unsigned int i=0; i<force.size(); ++i)
		if (ship.ID == force[i].ID) {
			force[i].update(ship);
			updated = true;
			break;
		}
		if (!updated) {
			force.push_back(T2(ship));
		}
}

void Commander::spreadShipInfo( void )
{
	for (unsigned int i=0; i<ours.size(); ++i) {
		ours[i].enemies = enemies;
		ours[i].islands = islands;
		ours[i].ours = &ours;
	}
}

void Commander::act( OSInterface* const system )
{
	float curTime = (clock()+0.0f)/CLOCKS_PER_SEC;
	if (curTime - lastActionTime < 0.1)
		return;
	lastActionTime = curTime;
	for (unsigned int i=0; i<ours.size(); ++i) {
		ours[i].act(system);
	}
}

void Commander::setTeam( int x )
{
	team = x;
}

void Commander::merge( int shipIdx )
{
}

void Commander::explore(vector<int> idxes) {
	for (unsigned int i=0; i<ours.size(); ++i)
		ours[i].keepDis = 300;

	if (dist2Island == NULL) {
		dist2Island = new float*[ours.size()];
		for (unsigned int i=0; i<ours.size(); ++i)
			dist2Island[i] = new float[islands.size()];
	}

	vector<pair<float, intPair>> disList;

	for (unsigned int i=0; i<ours.size(); ++i) {
		for (unsigned int j=0; j<islands.size(); ++j) {
			dist2Island[i][j] = (ours[i].pos - islands[j].pos).norm();
			disList.push_back(
				pair<float,intPair>(
					dist2Island[i][j],
					intPair(i, j)));
		}
	}
	sort(disList.begin(), disList.end());

#ifdef VERBOSE
	for (int i=0; i<disList.size(); ++i) {
		cout << "dis: " << disList[i].first << endl
			<< "ship: " << disList[i].second.first << endl
			<< "island: " << disList[i].second.second << endl;
	}
#endif

	bool usedShip[5], *usedIsland;
	memset(usedShip, 1, 5);
	for (unsigned int i=0; i<idxes.size(); ++i)
		usedShip[idxes[i]] = false;
	usedIsland = new bool[islands.size()];
	memset(usedIsland, 0, islands.size());
	for (unsigned int i=0; i<islands.size(); ++i) {
		if (islands[i].team == team) {
			usedIsland[i] = true;
		}
	}
	for (unsigned int i=0; i<disList.size(); ++i) {
		intPair sec = disList[i].second;
		if (!usedShip[sec.first] && !usedIsland[sec.second]) {
			ours[sec.first].takeIsland(sec.second);
			usedShip[sec.first] = true;
			usedIsland[sec.second] = true;
		}
	}

	delete[] usedIsland;
}

void Commander::regularCheck( void )
{
// 	vector<int> tmp;
// 	for (unsigned int i=0; i<ours.size(); ++i)
// 		if (ours[i].curCommand == Fatworm::IDLE)
// 			tmp.push_back(i);
// 	explore(tmp);

	for (unsigned int i=0; i<ours.size(); ++i)
		ours[i].regularCheck();
}

void Commander::makeOrder( void )
{
	for (unsigned int i=0; i<enemies.size(); ++i) {
		for (unsigned int j=0; j<ours.size(); ++j)
			if ((ours[j].pos - enemies[i].pos).norm() < RangeOfView) {
				ours[j].tracking();
			}
	}

// 	for (unsigned int i=0; i<groups.size(); ++i)
// 		if (groups[i].findEnemy()) {
// //			if (groups[i].enemyShips.size() < groups[i].size())
// 				groups[i].attack();
// 		}

// 	cout << "command: " << ours[0].curCommand << " " << Fatworm::ATTACK << endl;
// 	if (ours[2].curCommand != Fatworm::ATTACK && ours[2].curCommand != Fatworm::SEQ_MOV)
// 		ours[2].hold(TPoint(250, 0));
// 	if (ours[0].curCommand != Fatworm::ATTACK && ours[0].curCommand != Fatworm::SEQ_MOV)
// 		ours[0].hold(TPoint(250, 0));
//  	if (ours[4].curCommand != Fatworm::ATTACK && ours[4].curCommand != Fatworm::SEQ_MOV)
// 		ours[4].hold(TPoint(ours[4].pos.x, -500));

// 	cout << groups.size() << endl;
// 	for (unsigned int i=0; i<groups.size(); ++i) {
// 		for (unsigned int j=0; j<groups[i].size(); ++j)
// 			cout << groups[i].ships[j] << " ";
// 		cout << endl;
// 	}

}

void Commander::beforeUpdate( void )
{
	for (unsigned int i=0; i<ours.size(); ++i)
		ours[i].dead = true;
	
	enemies.clear();
}

void Commander::afterUpdate( void )
{
	int idx = 0;
	for (unsigned int i=0; i<ours.size(); ++i)
		if (!ours[i].dead) {
			if (idx == i) {
				++idx;
				continue;
			}
			ours[idx++] = ours[i];
		}
	int len = ours.size();
	for (int i=idx; i<len; ++i)
		ours.pop_back();

	spreadShipInfo();
	for (unsigned int i=0; i<ours.size(); ++i)
		ours[i].updateInfo();

	groupShips();
	for (unsigned int i=0; i<groups.size(); ++i)
		groups[i].updateInfo();
}

void Commander::groupShips( void )
{
	groups.clear();

	for (unsigned int i=0; i<ours.size(); ++i)
		groups.push_back(ShipGroup(i));
	bool merged = true;
	while (merged) {
		merged = false;
		for (unsigned int i=0; i<groups.size(); ++i) {
			for (unsigned int j=i+1; j<groups.size(); ++j)
				if (groups[i].dis(groups[j]) < CannonRange) {
					merged = true;
					groups[i].merge(groups[j]);
					groups[j] = groups[groups.size()-1];
					groups.pop_back();
				}
			if (merged) break;
		}
	}
}

Commander& Commander::getInstance( void )
{
	if (me == NULL) {
		me = new Commander;
		memset(me, 0, sizeof(Commander));
	}
	return *me;
}
Commander * Commander::me = NULL;
